package top.kaoshanji.p3ch13a;

import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.TextInputCallback;
import javax.security.auth.login.*;
import javax.security.auth.spi.LoginModule;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.Principal;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * 代码清单-p3ch13a-412页a：基于属性文件的登录模型的实现
 * author kaoshanji
 * ^_^
 * create time 2025/2/7 18:38
 */
public class PropertiesFileBasedLoginModule implements LoginModule {

    private CallbackHandler callbackHandler;
    private Subject subject;
    private Properties props = new Properties();
    private boolean authSucceeded = false;
    private String authUsername = null;

    @Override
    public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
        this.callbackHandler = callbackHandler;
        this.subject = subject;
        String propsFilePath = (String) options.get("properties.file.path");
        File propsFile = new File(propsFilePath);

        try {
            props.load(Files.newInputStream(propsFile.toPath()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public boolean login() throws LoginException {
        TextInputCallback userNameInputCallback = new TextInputCallback("用户名：");
        TextInputCallback passwordInputCallback = new TextInputCallback("密码：");

        try {
            callbackHandler.handle(new Callback[]{userNameInputCallback, passwordInputCallback});
        } catch (Exception e) {
            throw new LoginException(e.getMessage());
        }

        String userName = userNameInputCallback.getText();
        if (userName == null || userName.trim().isEmpty()) {
            throw new AccountException("用户名为空！");
        }

        if (!props.containsKey(userName)) {
            throw new AccountNotFoundException("该用户不存在！");
        }

        String password = passwordInputCallback.getText();
        if (password == null || password.trim().isEmpty()) {
            throw new CredentialException("密码为空！");
        }

        if (!password.equals(props.get(userName))) {
            throw new FailedLoginException("用户名和密码不匹配！");
        }

        authSucceeded = true;
        authUsername = userName;
        return true;
    }

    @Override
    public boolean commit() throws LoginException {
        if (authSucceeded) {
            this.subject.getPrincipals().add(new UserPrincipal(authUsername));
            authUsername = null;
            authSucceeded = false;
            return true;
        }
        return false;
    }

    @Override
    public boolean abort() throws LoginException {
        authUsername = null;
        if (authSucceeded) {
            authSucceeded = false;
            return true;
        }
        return false;
    }

    @Override
    public boolean logout() throws LoginException {
        Set<Principal> principals = subject.getPrincipals();
        Set<UserPrincipal> userPrincipals = subject.getPrincipals(UserPrincipal.class);
        for (UserPrincipal principal: userPrincipals) {
            if (principal.getName().equals(authUsername)) {
                principals.remove(principal);
                break;
            }
        }
        return true;
    }
}
